// file: arch/X86/arch/mm/swapswitch.c
// autor: jiangxinpeng
// time: 2021.1.11
// copyright: (C) 2020-2050 by jiangxinpeng,All right are reserved.

#include <arch/swapswitch.h>
#include <os/spinlock.h>
#include <arch/page.h>
#include <os/task.h>
#include <os/clock.h>
#include <os/debug.h>
#include <os/schedule.h>
#include <os/config.h>
#include <os/swap.h>
#include <lib/stdio.h>
#include <lib/string.h>
#include <lib/type.h>
#include <lib/list.h>

#if SWAP_ENABLE

#define PAGECOUNT_TIMEOUT 5 // 500 ticks per

// record found unused page info
LIST_HEAD(page_info_list); // the list of page free info
DEFINE_SPIN_LOCK_UNLOCK(page_info_lock);

timer_t *timer = NULL;

static int SwapSwitchTimerCount(timer_t *timer, void *arg)
{
    KPrint("[timer] run swap switch\n");

    if (!cur_task->vmm || !cur_task->vmm->page_storge)
    {
        TimerRestart(timer, PAGECOUNT_TIMEOUT);
        return -1;
    }

    if (list_empty(&cur_task->vmm->page_info_list))
    {
        TimerRestart(timer, PAGECOUNT_TIMEOUT);
        return -1;
    }

    page_info_t *page_info = NULL;

    SpinLock(&page_info_lock);
    list_traversal_all_owner_to_next(page_info, &cur_task->vmm->page_info_list, list)
    {
        if (*(page_info->pte) & PAGE_ACCESS)
        {
            page_info->count++;
            *(page_info->pte) &= ~PAGE_ACCESS;
        }

        if (page_info->count <= 0 - 1) // will may be overflow
            page_info->count = 0;
    }
    SpinUnlock(&page_info);
    TimerRestart(timer, PAGECOUNT_TIMEOUT);
}

void SwapSwitchInit()
{
    list_init(&page_info_list);
    timer = KMemAlloc(sizeof(timer_t));
    if (!timer)
        return -1;
    TimerInit(timer, PAGECOUNT_TIMEOUT, NULL, SwapSwitchTimerCount);
    TimerAdd(timer);
}

void SwapSwitchPageFree(page_info_t *page_info)
{
    if (!page_info)
        return;

    SpinLock(&page_info_lock);
    list_del(&page_info->list);
    SpinUnlock(&page_info_lock);
    KMemFree(&page_info);
}

page_info_t *SwapSwitchFindByPte(pte_t *pte)
{
    page_info_t *page_info, *next;

    if (list_empty(&page_info_list))
        return NULL;

    SpinLock(&page_info_lock);
    list_traversal_all_owner_to_next_safe(page_info, next, &page_info_list, list)
    {
        if (page_info->pte == pte)
        {
            SpinUnlock(&page_info_lock);
            return page_info;
        }
    }
    SpinUnlock(&page_info_lock);
    return NULL;
}

page_info_t *SwapSwitchPageAlloc(pte_t *pte)
{
    page_info_t *page_info = KMemAlloc(sizeof(page_info_t));
    if (!page_info)
    {
        KPrint("[pageswitch] alloc mem err\n");
        return -1;
    }

    page_info->count = 0;
    page_info->pte = pte;
    list_init(&page_info->list);
    SpinLock(&page_info_lock);
    list_add_tail(&page_info->list, &page_info_list);
    SpinUnlock(&page_info_lock);
}

uint64_t SwapSwitchPage()
{
}

#endif